//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//********************************************************* 

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;
using System;

namespace Microsoft.TridentWordAddIn.Presentation
{
    /// <summary>
    /// Description of CustomTabControl.
    /// </summary>
    [ToolboxBitmap(typeof(TabControl))]
    public partial class CustomTabControl : System.Windows.Forms.TabControl
    {
        bool fontAlignRight = false;
        private TabControlDisplayManager displayManager = TabControlDisplayManager.Custom;

        /// <summary>
        /// Tab Control Display type
        /// </summary>
        public enum TabControlDisplayManager
        {
            /// <summary>
            /// Default
            /// </summary>
            Default,

            /// <summary>
            /// Custom
            /// </summary>
            Custom
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CustomTabControl"/> class.
        /// </summary>
        public CustomTabControl()
            : base()
        {
            if (this.displayManager.Equals(TabControlDisplayManager.Custom))
            {
                this.SetStyle(ControlStyles.UserPaint, true);
                this.ItemSize = new Size(0, 15);
            }

            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.ResizeRedraw = true;
        }

        /// <summary>
        /// Gets or sets the display manager.
        /// </summary>
        /// <value>The display manager.</value>
        [System.ComponentModel.DefaultValue(typeof(TabControlDisplayManager), "Custom")]
        public TabControlDisplayManager DisplayManager
        {
            get
            {
                return this.displayManager;
            }

            set
            {
                if (this.displayManager != value)
                {
                    if (this.displayManager.Equals(TabControlDisplayManager.Custom))
                    {
                        this.SetStyle(ControlStyles.UserPaint, true);
                        this.ItemSize = new Size(0, 15);
                    }
                    else
                    {
                        this.SetStyle(ControlStyles.UserPaint, false);
                        this.ItemSize = new Size(0, 0);
                    }
                }
            }
        }

        /// <summary>
        /// Paints the background of the control.
        /// </summary>
        /// <param name="pevent">A <see cref="T:System.Windows.Forms.PaintEventArgs"/> that contains information about the control to paint.</param>
        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            if (this.DesignMode == true)
            {
                LinearGradientBrush backBrush = new LinearGradientBrush(
                    this.Bounds,
                    SystemColors.ControlLightLight,
                    SystemColors.ControlLight,
                    LinearGradientMode.Vertical);
                pevent.Graphics.FillRectangle(backBrush, this.Bounds);
                backBrush.Dispose();
            }
            else
            {
                this.InvokePaintBackground(this.Parent, pevent);
                this.InvokePaint(this.Parent, pevent);
            }
        }

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Forms.Control.Paint"/> event.
        /// </summary>
        /// <param name="e">A <see cref="T:System.Windows.Forms.PaintEventArgs"/> that contains the event data.</param>
        protected override void OnPaint(PaintEventArgs e)
        {
            this.PaintAllTheTabs(e);
            this.PaintTheTabPageBorder(e);
            this.PaintTheSelectedTab(e);
            //base.OnPaint(e);
        }

        /// <summary>
        /// Paints all the tabs.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Forms.PaintEventArgs"/> instance containing the event data.</param>
        private void PaintAllTheTabs(System.Windows.Forms.PaintEventArgs e)
        {
            if (this.TabCount > 0)
            {
                for (int index = 0; index < this.TabCount; index++)
                {
                    this.PaintTab(e, index);
                }
            }
        }

        /// <summary>
        /// Paints the tab.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Forms.PaintEventArgs"/> instance containing the event data.</param>
        /// <param name="index">The index.</param>
        private void PaintTab(System.Windows.Forms.PaintEventArgs e, int index)
        {
            fontAlignRight = false;
            GraphicsPath path = this.GetPath(index);
            this.PaintTabBackground(e.Graphics, index, path);
            this.PaintTabBorder(e.Graphics, index, path);
            this.PaintTabImage(e.Graphics, index);
            this.PaintTabText(e.Graphics, index);
        }

        /// <summary>
        /// Paints the tab background.
        /// </summary>
        /// <param name="graph">The graph.</param>
        /// <param name="index">The index.</param>
        /// <param name="path">The path.</param>
        private void PaintTabBackground(System.Drawing.Graphics graph, int index, System.Drawing.Drawing2D.GraphicsPath path)
        {
            Rectangle rect = this.GetTabRect(index);
            System.Drawing.Brush buttonBrush =
                new System.Drawing.Drawing2D.LinearGradientBrush(
                    rect,
                    SystemColors.ControlLightLight,
                    SystemColors.ControlLight,
                    LinearGradientMode.Vertical);

            if (index == this.SelectedIndex)
            {
                buttonBrush = new System.Drawing.SolidBrush(SystemColors.ControlLightLight);
            }

            graph.FillPath(buttonBrush, path);
            buttonBrush.Dispose();
        }

        /// <summary>
        /// Paints the tab border.
        /// </summary>
        /// <param name="graph">The graph.</param>
        /// <param name="index">The index.</param>
        /// <param name="path">The path.</param>
        private void PaintTabBorder(System.Drawing.Graphics graph, int index, System.Drawing.Drawing2D.GraphicsPath path)
        {
            Pen borderPen = new Pen(SystemColors.ControlDark);

            if (index == this.SelectedIndex)
            {
                borderPen = new Pen(Color.FromArgb(127, 157, 185));
            }

            graph.DrawPath(borderPen, path);
            borderPen.Dispose();
        }

        /// <summary>
        /// Paints the tab text.
        /// </summary>
        /// <param name="graph">The graph.</param>
        /// <param name="index">The index.</param>
        private void PaintTabImage(System.Drawing.Graphics graph, int index)
        {
            if (this.ImageList != null)
            {
                Image image = null;
                int imageIndex = this.TabPages[index].ImageIndex;
                if (imageIndex != -1)
                {
                    image = ImageList.Images[imageIndex];
                }
                else
                {
                    string imageKey = this.TabPages[index].ImageKey;
                    if (string.IsNullOrEmpty(imageKey))
                    {
                        return;
                    }

                    image = ImageList.Images[imageKey];
                }

                if (image != null)
                {
                    Rectangle rect = this.GetTabRect(index);
                    SizeF fontSize = graph.MeasureString(this.TabPages[index].Text, this.Font);
                    int start = (int)((rect.Width / 2) - (fontSize.Width / 2)) - 16;
                    if (start < 5)
                    {
                        fontAlignRight = true;
                        start = 9;
                    }

                    Rectangle rect2 = new Rectangle(rect.X + start, (rect.Height - 18), 16, 16);
                    graph.DrawImage(image, rect2);
                }
            }
        }

        /// <summary>
        /// Paints the tab text.
        /// </summary>
        /// <param name="graph">The graph.</param>
        /// <param name="index">The index.</param>
        private void PaintTabText(System.Drawing.Graphics graph, int index)
        {
            Rectangle rect = this.GetTabRect(index);
            string tabtext = this.TabPages[index].Text;
            System.Drawing.StringFormat format = new System.Drawing.StringFormat();
            if (fontAlignRight)
            {
                rect = new Rectangle(rect.X + 25, rect.Y, rect.Width, rect.Height);
                format.Alignment = StringAlignment.Near;
            }
            else
            {
                format.Alignment = StringAlignment.Center;
            }
            
            format.LineAlignment = StringAlignment.Center;
            format.Trimming = StringTrimming.EllipsisCharacter;

            SolidBrush forebrush = new SolidBrush(this.ForeColor);
            graph.DrawString(tabtext, this.Font, forebrush, rect, format);
            forebrush.Dispose();
        }

        /// <summary>
        /// Paints the tab page border.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Forms.PaintEventArgs"/> instance containing the event data.</param>
        private void PaintTheTabPageBorder(System.Windows.Forms.PaintEventArgs e)
        {
            if (this.TabCount > 0)
            {
                Rectangle borderRect = this.TabPages[this.SelectedIndex].Bounds;
                borderRect.Inflate(1, 1);
                ControlPaint.DrawBorder(e.Graphics, borderRect, Color.FromArgb(127, 157, 185), ButtonBorderStyle.Solid);
            }
        }

        /// <summary>
        /// Paints the selected tab.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Forms.PaintEventArgs"/> instance containing the event data.</param>
        private void PaintTheSelectedTab(System.Windows.Forms.PaintEventArgs e)
        {
            Rectangle selrect;
            int selrectRight = 0;

            switch (this.SelectedIndex)
            {
                case -1:
                    break;
                case 0:
                    selrect = this.GetTabRect(this.SelectedIndex);
                    selrectRight = selrect.Right;
                    e.Graphics.DrawLine(SystemPens.ControlLightLight, selrect.Left + 2, selrect.Bottom + 1, selrectRight - 2, selrect.Bottom + 1);
                    break;
                default:
                    selrect = this.GetTabRect(this.SelectedIndex);
                    selrectRight = selrect.Right;
                    e.Graphics.DrawLine(SystemPens.ControlLightLight, selrect.Left, selrect.Bottom + 1, selrectRight - 2, selrect.Bottom + 1);
                    break;
            }
        }

        /// <summary>
        /// Gets the path.
        /// </summary>
        /// <param name="index">The index.</param>
        /// <returns>GraphicsPath</returns>
        private System.Drawing.Drawing2D.GraphicsPath GetPath(int index)
        {
            System.Drawing.Drawing2D.GraphicsPath path = new System.Drawing.Drawing2D.GraphicsPath();
            Rectangle rect = this.GetTabRect(index);
            
            if (index == 0)
            {
                path.AddLine(rect.Left + 1, rect.Bottom + 1, rect.Left + 1, rect.Top + 2);
            }
            else
            {
                path.AddLine(rect.Left, rect.Bottom + 1, rect.Left, rect.Top + 2);
            }

            path.AddLine(rect.Left + 3, rect.Top, rect.Right - 3, rect.Top);
            path.AddLine(rect.Right - 1, rect.Top + 2, rect.Right - 1, rect.Bottom + 1);

            return path;
        }
    }
}